#ifndef __NURBS_PATCH_ENERGIES_NURBS__
#define __NURBS_PATCH_ENERGIES_NURBS__

#include "optimizer.h"

namespace Optimizer {
	class NurbsPatchFunctional;

	class NurbsPatchEvaluator : public Optimizer::PrimitiveEvaluator {
		public:
			NurbsPatchEvaluator(NurbsPatchFunctional* functional) : functional(functional) {}
			virtual nfloat f(const Attribute& attribute) const; //these three virtual function numerically integrate the functional over the nurbs patch 
			virtual Vector Gradient(const Attribute& attribute) const; 
			virtual Matrix Hessian(const Attribute& attribute) const; 
		private:
			NurbsPatchFunctional* functional;
	};
	
	class NurbsPatchFunctional {
		public:
			virtual nfloat Energy(const SNurbs* e, const math::Vec2ui& index, const std::string& attribute) const = 0; //index is the quadrature sample where energy is evaluated
			virtual Vector EnergyGradient(const SNurbs* e, const math::Vec2ui& index, const std::string& attribute) const = 0;
	};
	
	class WillmoreEnergyFunctional : public NurbsPatchFunctional {
		public:
			virtual nfloat Energy(const SNurbs* e, const math::Vec2ui& index, const std::string& attribute) const;
			virtual Vector EnergyGradient(const SNurbs* e, const math::Vec2ui& index, const std::string& attribute) const;
	};

	class MVSEnergyFunctional : public NurbsPatchFunctional {
		public:
			virtual nfloat Energy(const SNurbs* e, const math::Vec2ui& index, const std::string& attribute) const;
			virtual Vector EnergyGradient(const SNurbs* e, const math::Vec2ui& index, const std::string& attribute) const;
	};

	class MehlumTarrouEnergyFunctional : public NurbsPatchFunctional {
		public:
			virtual nfloat Energy(const SNurbs* e, const math::Vec2ui& index, const std::string& attribute) const;
			virtual Vector EnergyGradient(const SNurbs* e, const math::Vec2ui& index, const std::string& attribute) const;
	};
}

#endif //__NURBS_PATCH_ENERGIES_NURBS__
